package drds.data_propagate.binlog_event.protogenesis;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.BitSet;

public class Buffer {

    /* The max ulonglong - 0x ff ff ff ff ff ff ff ff */
    public static final BigInteger BIGINT_MAX_VALUE = new BigInteger("18446744073709551615");
    public static final long NULL_LENGTH = ((long) ~0);
    /* default ANSI charset */
    public static final String ISO_8859_1 = "ISO-8859-1";
    /* decimal representation */
    public static final int DIG_PER_DEC1 = 9;
    public static final int DIG_BASE = 1000000000;
    public static final int DIG_MAX = DIG_BASE - 1;
    public static final int dig2bytes[] = {0, 1, 1, 2, 2, 3, 3, 4, 4, 4};
    public static final int powers10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
    public static final int DIG_PER_INT32 = 9;
    public static final int SIZE_OF_INT32 = 4;
    //
    protected byte[] bytes;
    /**
     * 有效起始位置,非基准指针,需要使用effectiveInitialIndexOffset进行指代偏移量。
     */
    protected int effectiveInitialIndex;
    /**
     * 读写指针分界的地方,该指针前为已读部分,后为未读部分.定义该指针为基本指定,各种方法前面不用增加其他的pre或者post...。
     */
    protected int readedIndex;
    protected int limit;
    //
    protected int semiValue;

    protected Buffer() {
    }

    public Buffer(byte[] bytes, final int effectiveInitialIndex, final int limit) {
        if (effectiveInitialIndex + limit > bytes.length) {
            throw new IllegalArgumentException("capacity excceed: " + (effectiveInitialIndex + limit));
        }
        this.bytes = bytes;
        this.effectiveInitialIndex = effectiveInitialIndex;
        this.readedIndex = effectiveInitialIndex;
        this.limit = limit;
    }

    /**
     * Return 16-bit signed int from bytes. (big-endian)
     */
    private static final int getBigEndian16SignedInt(byte[] bytes, final int offset) {
        return ((bytes[offset]) << 8) | //
                (0xff & bytes[offset + 1]);
    }

    /**
     * Return 24-bit signed int from bytes. (big-endian)
     */
    private static final int getBigEndian24SignedInt(byte[] bytes, final int offset) {
        return (bytes[offset] << 16) | //
                ((0xff & bytes[offset + 1]) << 8) | //
                (0xff & bytes[offset + 2]);//
    }

    /**
     * Return 32-bit signed int from bytes. (big-endian)
     */
    private static final int getBigEndian32SignedInt(byte[] bytes, final int offset) {
        return (bytes[offset] << 24) | //
                ((0xff & bytes[offset + 1]) << 16) | //
                ((0xff & bytes[offset + 2]) << 8) | //
                (0xff & bytes[offset + 3]);//
    }

    /**
     * Return n bytes in this bytes.
     */
    public final Buffer duplicateFromEffectiveInitialIndexOffset(final int effectiveInitialIndexOffset,
                                                                 final int length) {
        if (effectiveInitialIndexOffset + length > limit) {
            throw new IllegalArgumentException("newLimit excceed: " + (effectiveInitialIndexOffset + length));
        }

        // 'copy data' avoid bytes modified.
        final int index = this.effectiveInitialIndex + effectiveInitialIndexOffset;
        byte[] bytes = Arrays.copyOfRange(this.bytes, index, index + length);
        return new Buffer(bytes, 0, length);
    }

    /**
     * Return next n bytes in this bytes.
     */
    public final Buffer duplicateFromEffectiveInitialIndexOffset() {
        // XXX: Do momery copy avoid bytes modified.
        byte[] bytes = Arrays.copyOfRange(this.bytes, effectiveInitialIndex, effectiveInitialIndex + limit);
        return new Buffer(bytes, 0, limit);
    }

    /**
     * Return next n bytes in this bytes.
     */
    public final Buffer duplicate(final int length) {
        if (readedIndex + length > effectiveInitialIndex + limit) {
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex + length - effectiveInitialIndex));
        }
        final int end = readedIndex + length;
        byte[] bytes = Arrays.copyOfRange(this.bytes, readedIndex, end);
        Buffer buffer = new Buffer(bytes, 0, length);
        readedIndex = end;
        return buffer;
    }

    public final int capacity() {
        return bytes.length;
    }

    public final int readed() {
        return readedIndex - effectiveInitialIndex;
    }

    public final Buffer newReadedIndex(final int effectiveInitialIndexOffset) {
        if (effectiveInitialIndexOffset > limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException("newLimit excceed: " + effectiveInitialIndexOffset);

        this.readedIndex = effectiveInitialIndex + effectiveInitialIndexOffset;
        return this;
    }

    public final Buffer forward(final int length) {
        if (readedIndex + length > effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex + length - effectiveInitialIndex));

        this.readedIndex += length;
        return this;
    }

    /**
     * Consume this bytes, moving $ and readedIndex.(核心方法)
     */
    public final Buffer consume(final int length) {
        if (limit > length) {
            limit -= length;
            effectiveInitialIndex += length;
            readedIndex = effectiveInitialIndex;
            return this;
        } else if (limit == length) {
            limit = 0;
            effectiveInitialIndex = 0;
            readedIndex = 0;
            return this;
        } else {
            /* Should not happen. */
            throw new IllegalArgumentException("newLimit excceed: " + length);
        }
    }

    public final Buffer resetReadedIndex() {
        readedIndex = effectiveInitialIndex;
        return this;
    }

    public final int limit() {
        return limit;
    }

    public final Buffer newLimit(int newLimit) {
        if (effectiveInitialIndex + newLimit > bytes.length || newLimit < 0)
            throw new IllegalArgumentException("capacity excceed: " + (effectiveInitialIndex + newLimit));

        limit = newLimit;
        return this;
    }

    public final int remaining() {
        return limit + effectiveInitialIndex - readedIndex;
    }

    public final boolean hasRemaining() {
        return readedIndex < limit + effectiveInitialIndex;
    }

    /**
     * <pre>
     * ====================================================================================================
     *  小端/大端 无符号/有符号 effectiveInitialIndex/readedIndex
     * ====================================================================================================
     * </pre>
     */
    /**
     * <pre>
     * ====================================================================================================
     * byte(无大端和小端)
     * ====================================================================================================
     * </pre>
     */
    /**
     * Return 8-bit signed int from bytes.
     */
    public final int get8SignedInt(final int effectiveInitialIndexOffset) {
        if (effectiveInitialIndexOffset >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException("newLimit excceed: " + effectiveInitialIndexOffset);

        return bytes[effectiveInitialIndex + effectiveInitialIndexOffset];
    }

    /**
     * Return next 8-bit signed int from bytes.
     */
    public final int getNext8SignedInt() {
        if (readedIndex >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex));

        return bytes[readedIndex++];
    }

    /**
     * Return 8-bit unsigned int from bytes.
     */
    public final int get8UnsignedInt(final int effectiveInitialIndexOffset) {
        if (effectiveInitialIndexOffset >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException("newLimit excceed: " + effectiveInitialIndexOffset);

        return 0xff & bytes[effectiveInitialIndex + effectiveInitialIndexOffset];
    }

    /**
     * Return next 8-bit unsigned int from bytes.
     */
    public final int getNext8UnsignedInt() {
        if (readedIndex >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex));

        return 0xff & bytes[readedIndex++];
    }
    /**
     * <pre>
     * ====================================================================================================
     * 2byte
     * ====================================================================================================
     * </pre>
     */
    // ###小端

    /**
     * Return 16-bit signed int from bytes. (little-endian)
     */
    public final int getLittleEndian16SignedInt(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 1 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 1)));

        byte[] bytes = this.bytes;
        return (0xff & bytes[index]) | //
                ((bytes[index + 1]) << 8);
    }

    /**
     * Return next 16-bit signed int from bytes. (little-endian)
     */
    public final int getNextLittleEndian16SignedInt() {
        if (readedIndex + 1 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 1));

        byte[] bytes = this.bytes;
        return (0xff & bytes[readedIndex++]) | //
                ((bytes[readedIndex++]) << 8);
    }

    /**
     * Return 16-bit unsigned int from bytes. (little-endian)
     */
    public final int getLittleEndian16UnsignedInt(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 1 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 1)));

        byte[] bytes = this.bytes;
        return (0xff & bytes[index]) | //
                ((0xff & bytes[index + 1]) << 8);
    }

    /**
     * Return next 16-bit unsigned int from bytes. (little-endian)
     */
    public final int getNextLittleEndian16UnsignedInt() {
        if (readedIndex + 1 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 1));

        byte[] bytes = this.bytes;
        return (0xff & bytes[readedIndex++]) | //
                ((0xff & bytes[readedIndex++]) << 8);
    }
    // ###大端
    // 这里是小端

    /**
     * Return 16-bit signed int from bytes. (big-endian)
     */
    public final int getBigEndian16SignedInt(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 1 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 1)));

        byte[] bytes = this.bytes;
        return (0xff & bytes[index + 1]) | //
                ((bytes[index]) << 8);
    }

    /**
     * Return next 16-bit signed int from bytes. (big-endian)
     */
    public final int getNextBigEndian16SignedInt() {
        if (readedIndex + 1 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 1));

        byte[] bytes = this.bytes;
        return (bytes[readedIndex++] << 8) | //
                (0xff & bytes[readedIndex++]);
    }
    // 这里是小端

    /**
     * Return 16-bit unsigned int from bytes. (big-endian)
     */
    public final int getBigEndian16UnsignedInt(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 1 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 1)));

        byte[] bytes = this.bytes;
        return (0xff & bytes[index + 1]) | //
                ((0xff & bytes[index]) << 8);
    }

    /**
     * Return next 16-bit unsigned int from bytes. (big-endian)
     */
    public final int getNextBigEndian16UnsignedInt() {
        if (readedIndex + 1 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 1));

        byte[] bytes = this.bytes;
        return ((0xff & bytes[readedIndex++]) << 8) | //
                (0xff & bytes[readedIndex++]);
    }
    /**
     * <pre>
     * ====================================================================================================
     * 3byte
     * ====================================================================================================
     * </pre>
     */
    // ###小端

    /**
     * Return 24-bit signed int from bytes. (little-endian)
     */
    public final int getLittleEndian24SignedInt(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 2 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 2)));

        byte[] bytes = this.bytes;
        return (0xff & bytes[index]) | //
                ((0xff & bytes[index + 1]) << 8) | //
                ((bytes[index + 2]) << 16);
    }

    /**
     * Return next 24-bit signed int from bytes. (little-endian)
     */
    public final int getNextLittleEndian24SignedInt() {
        if (readedIndex + 2 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 2));

        byte[] bytes = this.bytes;
        return (0xff & bytes[readedIndex++]) | //
                ((0xff & bytes[readedIndex++]) << 8) | //
                ((bytes[readedIndex++]) << 16);
    }

    /**
     * Return 24-bit unsigned int from bytes. (little-endian)
     */
    public final int getLittleEndian24UnsignedInt(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 2 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 2)));

        byte[] bytes = this.bytes;
        return (0xff & bytes[index]) | //
                ((0xff & bytes[index + 1]) << 8) | //
                ((0xff & bytes[index + 2]) << 16);
    }

    /**
     * Return next 24-bit unsigned int from bytes. (little-endian)
     */
    public final int getNextLittleEndian24UnsignedInt() {
        if (readedIndex + 2 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 2));

        byte[] bytes = this.bytes;
        return (0xff & bytes[readedIndex++]) | //
                ((0xff & bytes[readedIndex++]) << 8) | //
                ((0xff & bytes[readedIndex++]) << 16);
    }
    // ###大端

    /**
     * Return 24-bit signed int from bytes. (big-endian)
     */
    public final int getBigEndian24SignedInt(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 2 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 2)));

        byte[] bytes = this.bytes;
        return ((bytes[index]) << 16) | //
                ((0xff & bytes[index + 1]) << 8) | //
                (0xff & bytes[index + 2]);
    }

    /**
     * Return next 24-bit signed int from bytes. (big-endian)
     */
    public final int getNextBigEndian24SignedInt() {
        if (readedIndex + 2 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 2));

        byte[] bytes = this.bytes;
        return ((bytes[readedIndex++]) << 16) | //
                ((0xff & bytes[readedIndex++]) << 8) | //
                (0xff & bytes[readedIndex++]);
    }

    /**
     * Return 24-bit unsigned int from bytes. (big-endian)
     */
    public final int getBigEndian24UnsignedInt(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 2 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 2)));

        byte[] bytes = this.bytes;
        return ((0xff & bytes[index]) << 16) | //
                ((0xff & bytes[index + 1]) << 8) | //
                (0xff & bytes[index + 2]);
    }

    /**
     * Return next 24-bit unsigned int from bytes. (big-endian)
     */
    public final int getNextBigEndian24UnsignedInt() {
        if (readedIndex + 2 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 2));

        byte[] bytes = this.bytes;
        return ((0xff & bytes[readedIndex++]) << 16) | //
                ((0xff & bytes[readedIndex++]) << 8) | //
                (0xff & bytes[readedIndex++]);
    }
    /**
     * <pre>
     * ====================================================================================================
     * 4byte
     * ====================================================================================================
     * </pre>
     */
    // ###小端

    /**
     * Return 32-bit signed int from bytes. (little-endian)
     */
    public final int getLittleEndian32SignedInt(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 3 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 3)));

        byte[] bytes = this.bytes;
        return (0xff & bytes[index]) | //
                ((0xff & bytes[index + 1]) << 8) | //
                ((0xff & bytes[index + 2]) << 16) | //
                ((bytes[index + 3]) << 24);
    }

    /**
     * Return next 32-bit signed int from bytes. (little-endian)
     */
    public final int getNextLittleEndian32SignedInt() {
        if (readedIndex + 3 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 3));

        byte[] bytes = this.bytes;
        return (0xff & bytes[readedIndex++]) | //
                ((0xff & bytes[readedIndex++]) << 8) | //
                ((0xff & bytes[readedIndex++]) << 16) | //
                ((bytes[readedIndex++]) << 24);
    }

    /**
     * Return 32-bit unsigned int from bytes. (little-endian)
     */
    public final long getLittleEndian32UnsignedLong(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 3 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 3)));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[index])) | //
                ((long) (0xff & bytes[index + 1]) << 8) | //
                ((long) (0xff & bytes[index + 2]) << 16) | //
                ((long) (0xff & bytes[index + 3]) << 24);
    }

    /**
     * Return next 32-bit unsigned int from bytes. (little-endian)
     */
    public final long getNextLittleEndian32UnsignedLong() {
        if (readedIndex + 3 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 3));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[readedIndex++])) | //
                ((long) (0xff & bytes[readedIndex++]) << 8) | //
                ((long) (0xff & bytes[readedIndex++]) << 16) | //
                ((long) (0xff & bytes[readedIndex++]) << 24);//
    }

    // ###大端

    /**
     * Return 32-bit signed int from bytes. (big-endian)
     */
    public final int getBigEndian32SignedInt(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 3 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 3)));

        byte[] bytes = this.bytes;
        return ((bytes[index]) << 24) | //
                ((0xff & bytes[index + 1]) << 16) | //
                ((0xff & bytes[index + 2]) << 8) | //
                (0xff & bytes[index + 3]);
    }

    /**
     * Return next 32-bit signed int from bytes. (big-endian)
     */
    public final int getNextBigEndian32SignedInt() {
        if (readedIndex + 3 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 3));

        byte[] bytes = this.bytes;
        return ((bytes[readedIndex++]) << 24) | //
                ((0xff & bytes[readedIndex++]) << 16) | //
                ((0xff & bytes[readedIndex++]) << 8) | //
                (0xff & bytes[readedIndex++]);
    }

    /**
     * Return 32-bit unsigned int from bytes. (big-endian)
     */
    public final long getBigEndian32UnsignedLong(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 3 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 3)));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[index]) << 24) | //
                ((long) (0xff & bytes[index + 1]) << 16) | //
                ((long) (0xff & bytes[index + 2]) << 8) | //
                ((long) (0xff & bytes[index + 3]));
    }

    /**
     * Return next 32-bit unsigned int from bytes. (big-endian)
     */
    public final long getNextBigEndian32UnsignedLong() {
        if (readedIndex + 3 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 3));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[readedIndex++]) << 24) | //
                ((long) (0xff & bytes[readedIndex++]) << 16) | //
                ((long) (0xff & bytes[readedIndex++]) << 8) | //
                ((long) (0xff & bytes[readedIndex++]));
    }

    /**
     * <pre>
     * ====================================================================================================
     * 5byte
     * ====================================================================================================
     * </pre>
     */
    /**
     * Return 40-bit unsigned int from bytes. (little-endian)
     */
    public final long getLittleEndian40UnsignedLong(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 4 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 4)));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[index])) | //
                ((long) (0xff & bytes[index + 1]) << 8) | //
                ((long) (0xff & bytes[index + 2]) << 16) | //
                ((long) (0xff & bytes[index + 3]) << 24) | //
                ((long) (0xff & bytes[index + 4]) << 32);
    }

    /**
     * Return next 40-bit unsigned int from bytes. (little-endian)
     */
    public final long getNextLittleEndian40UnsignedLong() {
        if (readedIndex + 4 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 4));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[readedIndex++])) | //
                ((long) (0xff & bytes[readedIndex++]) << 8) | //
                ((long) (0xff & bytes[readedIndex++]) << 16) | //
                ((long) (0xff & bytes[readedIndex++]) << 24) | //
                ((long) (0xff & bytes[readedIndex++]) << 32);
    }

    /**
     * Return 40-bit unsigned int from bytes. (big-endian)
     */
    public final long getBigEndian40UnsignedLong(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 4 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 4)));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[index]) << 32) | //
                ((long) (0xff & bytes[index + 1]) << 24) | //
                ((long) (0xff & bytes[index + 2]) << 16) | //
                ((long) (0xff & bytes[index + 3]) << 8) | //
                ((long) (0xff & bytes[index + 4]));
    }

    /**
     * Return next 40-bit unsigned int from bytes. (big-endian)
     */
    public final long getNextBigEndian40UnsignedLong() {
        if (readedIndex + 4 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 4));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[readedIndex++]) << 32) | //
                ((long) (0xff & bytes[readedIndex++]) << 24) | //
                ((long) (0xff & bytes[readedIndex++]) << 16) | //
                ((long) (0xff & bytes[readedIndex++]) << 8) | //
                ((long) (0xff & bytes[readedIndex++]));
    }
    /**
     * <pre>
     * ====================================================================================================
     * 6byte
     * ====================================================================================================
     * </pre>
     */
    // ###小端

    /**
     * Return 48-bit signed long from bytes. (little-endian)
     */
    public final long getLittleEndian48SignedLong(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 5 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 5)));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[index])) | //
                ((long) (0xff & bytes[index + 1]) << 8) | //
                ((long) (0xff & bytes[index + 2]) << 16) | //
                ((long) (0xff & bytes[index + 3]) << 24) | //
                ((long) (0xff & bytes[index + 4]) << 32) | //
                ((long) (bytes[index + 5]) << 40);
    }

    /**
     * Return next 48-bit signed long from bytes. (little-endian)
     */
    public final long getNextLittleEndian48SignedLong() {
        if (readedIndex + 5 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 5));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[readedIndex++])) | //
                ((long) (0xff & bytes[readedIndex++]) << 8) | //
                ((long) (0xff & bytes[readedIndex++]) << 16) | //
                ((long) (0xff & bytes[readedIndex++]) << 24) | //
                ((long) (0xff & bytes[readedIndex++]) << 32) | //
                ((long) (bytes[readedIndex++]) << 40);
    }

    /**
     * Return 48-bit unsigned long from bytes. (little-endian)
     */
    public final long getLittleEndian48UnsignedLong(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 5 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 5)));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[index])) | //
                ((long) (0xff & bytes[index + 1]) << 8) | //
                ((long) (0xff & bytes[index + 2]) << 16) | //
                ((long) (0xff & bytes[index + 3]) << 24) | //
                ((long) (0xff & bytes[index + 4]) << 32) | //
                ((long) (0xff & bytes[index + 5]) << 40);
    }

    /**
     * Return next 48-bit unsigned long from bytes. (little-endian)
     */
    public final long getNextLittleEndian48UnsignedLong() {
        if (readedIndex + 5 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 5));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[readedIndex++])) | //
                ((long) (0xff & bytes[readedIndex++]) << 8) | //
                ((long) (0xff & bytes[readedIndex++]) << 16) | //
                ((long) (0xff & bytes[readedIndex++]) << 24) | //
                ((long) (0xff & bytes[readedIndex++]) << 32) | //
                ((long) (0xff & bytes[readedIndex++]) << 40);
    }
    // ###大端

    /**
     * Return 48-bit signed long from bytes. (big-endian)
     */
    public final long getBigEndian48SignedLong(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 5 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 5)));

        byte[] bytes = this.bytes;
        return ((long) (bytes[index]) << 40) | //
                ((long) (0xff & bytes[index + 1]) << 32) | //
                ((long) (0xff & bytes[index + 2]) << 24) | //
                ((long) (0xff & bytes[index + 3]) << 16) | //
                ((long) (0xff & bytes[index + 4]) << 8) | //
                ((long) (0xff & bytes[index + 5]));
    }

    /**
     * Return next 48-bit signed long from bytes. (Big-endian)
     */
    public final long getNextBigEndian48SignedLong() {
        if (readedIndex + 5 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 5));

        byte[] bytes = this.bytes;
        return ((long) (bytes[readedIndex++]) << 40) | //
                ((long) (0xff & bytes[readedIndex++]) << 32) | //
                ((long) (0xff & bytes[readedIndex++]) << 24) | //
                ((long) (0xff & bytes[readedIndex++]) << 16) | //
                ((long) (0xff & bytes[readedIndex++]) << 8) | //
                ((long) (0xff & bytes[readedIndex++]));
    }

    /**
     * Return 48-bit unsigned long from bytes. (big-endian)
     */
    public final long getBigEndian48UnsignedLong(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 5 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 5)));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[index]) << 40) | //
                ((long) (0xff & bytes[index + 1]) << 32) | //
                ((long) (0xff & bytes[index + 2]) << 24) | //
                ((long) (0xff & bytes[index + 3]) << 16) | //
                ((long) (0xff & bytes[index + 4]) << 8) | //
                ((long) (0xff & bytes[index + 5]));
    }

    /**
     * Return next 48-bit unsigned long from bytes. (big-endian)
     */
    public final long getNextBigEndian48UnsignedLong() {
        if (readedIndex + 5 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 5));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[readedIndex++]) << 40) | //
                ((long) (0xff & bytes[readedIndex++]) << 32) | //
                ((long) (0xff & bytes[readedIndex++]) << 24) | //
                ((long) (0xff & bytes[readedIndex++]) << 16) | //
                ((long) (0xff & bytes[readedIndex++]) << 8) | //
                ((long) (0xff & bytes[readedIndex++]));
    }
    /**
     * <pre>
     * ====================================================================================================
     * 7byte
     * ====================================================================================================
     * </pre>
     */
    // ###小端

    /**
     * Return 56-bit unsigned int from bytes. (little-endian)
     */
    public final long getLittleEndian56UnsignedLong(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 6 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 6)));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[index])) | //
                ((long) (0xff & bytes[index + 1]) << 8) | //
                ((long) (0xff & bytes[index + 2]) << 16) | //
                ((long) (0xff & bytes[index + 3]) << 24) | //
                ((long) (0xff & bytes[index + 4]) << 32) | //
                ((long) (0xff & bytes[index + 5]) << 40) | //
                ((long) (0xff & bytes[index + 6]) << 48);
    }

    /**
     * Return next 56-bit unsigned int from bytes. (little-endian)
     */
    public final long getNextLittleEndian56UnsignedLong() {
        if (readedIndex + 6 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 6));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[readedIndex++])) | //
                ((long) (0xff & bytes[readedIndex++]) << 8) | //
                ((long) (0xff & bytes[readedIndex++]) << 16) | //
                ((long) (0xff & bytes[readedIndex++]) << 24) | //
                ((long) (0xff & bytes[readedIndex++]) << 32) | //
                ((long) (0xff & bytes[readedIndex++]) << 40) | //
                ((long) (0xff & bytes[readedIndex++]) << 48);
    }
    // ###大端

    /**
     * Return 56-bit unsigned int from bytes. (big-endian)
     */
    public final long getBigEndian56UnsignedLong(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 6 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 6)));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[index + 6])) | //
                ((long) (0xff & bytes[index + 5]) << 8) | //
                ((long) (0xff & bytes[index + 4]) << 16) | //
                ((long) (0xff & bytes[index + 3]) << 24) | //
                ((long) (0xff & bytes[index + 2]) << 32) | //
                ((long) (0xff & bytes[index + 1]) << 40) | //
                ((long) (0xff & bytes[index]) << 48);
    }

    /**
     * Return next 56-bit unsigned int from bytes. (big-endian)
     */
    public final long getNextBigEndian56UnsignedLong() {
        if (readedIndex + 6 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 6));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[readedIndex++]) << 48) | //
                ((long) (0xff & bytes[readedIndex++]) << 40) | //
                ((long) (0xff & bytes[readedIndex++]) << 32) | //
                ((long) (0xff & bytes[readedIndex++]) << 24) | //
                ((long) (0xff & bytes[readedIndex++]) << 16) | //
                ((long) (0xff & bytes[readedIndex++]) << 8) | //
                ((long) (0xff & bytes[readedIndex++]));
    }

    // 大端
    /**
     * <pre>
     * ====================================================================================================
     * 8byte
     * ====================================================================================================
     * </pre>
     */
    /**
     * Return 64-bit signed long from bytes. (little-endian)
     */
    public final long getLittleEndian64SignedLong(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 7 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 7)));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[index])) | //
                ((long) (0xff & bytes[index + 1]) << 8) | //
                ((long) (0xff & bytes[index + 2]) << 16) | //
                ((long) (0xff & bytes[index + 3]) << 24) | //
                ((long) (0xff & bytes[index + 4]) << 32) | //
                ((long) (0xff & bytes[index + 5]) << 40) | //
                ((long) (0xff & bytes[index + 6]) << 48) | //
                ((long) (bytes[index + 7]) << 56);
    }

    /**
     * Return next 64-bit signed long from bytes. (little-endian)
     */
    public final long getNextLittleEndian64SignedLong() {
        if (readedIndex + 7 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 7));

        byte[] bytes = this.bytes;
        return ((long) (0xff & bytes[readedIndex++])) | //
                ((long) (0xff & bytes[readedIndex++]) << 8) | //
                ((long) (0xff & bytes[readedIndex++]) << 16) | //
                ((long) (0xff & bytes[readedIndex++]) << 24) | //
                ((long) (0xff & bytes[readedIndex++]) << 32) | //
                ((long) (0xff & bytes[readedIndex++]) << 40) | //
                ((long) (0xff & bytes[readedIndex++]) << 48) | //
                ((long) (bytes[readedIndex++]) << 56);
    }

    /**
     * Return 64-bit signed long from bytes. (big-endian)
     */
    public final long getBigEndian64SignedLong(final int effectiveInitialIndexOffset) {
        final int index = effectiveInitialIndex + effectiveInitialIndexOffset;

        if (effectiveInitialIndexOffset + 7 >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + 7)));

        byte[] bytes = this.bytes;
        return ((long) (bytes[index]) << 56) | //
                ((long) (0xff & bytes[index + 1]) << 48) | //
                ((long) (0xff & bytes[index + 2]) << 40) | //
                ((long) (0xff & bytes[index + 3]) << 32) | //
                ((long) (0xff & bytes[index + 4]) << 24) | //
                ((long) (0xff & bytes[index + 5]) << 16) | //
                ((long) (0xff & bytes[index + 6]) << 8) | //
                ((long) (0xff & bytes[index + 7]));
    }

    /**
     * Return next 64-bit signed long from bytes. (big-endian)
     */
    public final long getNextBigEndian64SignedLong() {
        if (readedIndex + 7 >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex - effectiveInitialIndex + 7));

        byte[] bytes = this.bytes;
        return ((long) (bytes[readedIndex++]) << 56) | //
                ((long) (0xff & bytes[readedIndex++]) << 48) | //
                ((long) (0xff & bytes[readedIndex++]) << 40) | //
                ((long) (0xff & bytes[readedIndex++]) << 32) | //
                ((long) (0xff & bytes[readedIndex++]) << 24) | //
                ((long) (0xff & bytes[readedIndex++]) << 16) | //
                ((long) (0xff & bytes[readedIndex++]) << 8) | //
                ((long) (0xff & bytes[readedIndex++]));
    }
    // end all

    /**
     * Return 64-bit unsigned long from bytes. (little-endian)
     */
    public final BigInteger getLittleEndian64UnsignedLong(final int effectiveInitialIndexOffset) {
        final long long64 = getLittleEndian64SignedLong(effectiveInitialIndexOffset);

        return (long64 >= 0) ? BigInteger.valueOf(long64) : BIGINT_MAX_VALUE.add(BigInteger.valueOf(1 + long64));
    }

    /**
     * Return 64-bit unsigned long from bytes. (big-endian)
     */
    public final BigInteger getBigEndian64UnsignedLong(final int effectiveInitialIndexOffset) {
        final long long64 = getBigEndian64SignedLong(effectiveInitialIndexOffset);

        return (long64 >= 0) ? BigInteger.valueOf(long64) : BIGINT_MAX_VALUE.add(BigInteger.valueOf(1 + long64));
    }

    /**
     * Return next 64-bit unsigned long from bytes. (little-endian)
     */
    public final BigInteger getNextLittleEndian64UnsignedLong() {
        final long long64 = getNextLittleEndian64SignedLong();

        return (long64 >= 0) ? BigInteger.valueOf(long64) : BIGINT_MAX_VALUE.add(BigInteger.valueOf(1 + long64));
    }

    /**
     * Return next 64-bit unsigned long from bytes. (big-endian)
     */
    public final BigInteger getNextBigEndian64UnsignedLong() {
        final long long64 = getNextBigEndian64SignedLong();

        return (long64 >= 0) ? BigInteger.valueOf(long64) : BIGINT_MAX_VALUE.add(BigInteger.valueOf(1 + long64));
    }

    /**
     * Return 32-bit float from bytes. (little-endian)
     */
    public final float getLittleEndian32Float(final int effectiveInitialIndexOffset) {
        return Float.intBitsToFloat(getLittleEndian32SignedInt(effectiveInitialIndexOffset));
    }

    /**
     * Return next 32-bit float from bytes. (little-endian)
     */
    public final float getNextLittleEndian32Float() {
        return Float.intBitsToFloat(getNextLittleEndian32SignedInt());
    }

    /**
     * Return 64-bit double from bytes. (little-endian)
     */
    public final double getLittleEndian64Double(final int effectiveInitialIndexOffset) {
        return Double.longBitsToDouble(getLittleEndian64SignedLong(effectiveInitialIndexOffset));
    }

    /**
     * Return next 64-bit double from bytes. (little-endian)
     */
    public final double getNextLittleEndian64Double() {
        return Double.longBitsToDouble(getNextLittleEndian64SignedLong());
    }

    /**
     * Return packed number from bytes. (little-endian) A Packed Integer has the
     * capacity of storing up decode 8-byte integers, while small integers still can use
     * 1, 3, or 4 bytes. The value of the first byte determines how decode read the
     * number, according decode the following tableName.
     * <ul>
     * <li>0-250 The first byte is the number (in the range 0-250). No additional
     * bytes are used.</li>
     * <li>252 Two more bytes are used. The number is in the range 251-0xffff.</li>
     * <li>253 Three more bytes are used. The number is in the range
     * 0xffff-0xffffff.</li>
     * <li>254 Eight more bytes are used. The number is in the range
     * 0xffffff-0xffffffffffffffff.</li>
     * </ul>
     * That representation allows a first byte value of 251 decode represent the SQL
     * NULL value.
     */
    public final long getPackedLength(final int effectiveInitialIndexOffset) {
        final int $ = get8UnsignedInt(effectiveInitialIndexOffset);
        if ($ < 251)
            return $;

        switch ($) {
            case 251:
                return NULL_LENGTH;
            case 252:
                return getLittleEndian16UnsignedInt(effectiveInitialIndexOffset + 1);
            case 253:
                return getLittleEndian24UnsignedInt(effectiveInitialIndexOffset + 1);
            default: /* Must be 254 executeTimeStamp here */
                return getLittleEndian32UnsignedLong(effectiveInitialIndexOffset + 1);
        }
    }

    /**
     * Return next packed number from bytes. (little-endian)
     */
    public final long getPackedLength() {
        final int $ = getNext8UnsignedInt();
        if ($ < 251)
            return $;

        switch ($) {
            case 251:
                return NULL_LENGTH;
            case 252:
                return getNextLittleEndian16UnsignedInt();
            case 253:
                return getNextLittleEndian24UnsignedInt();
            default: /* Must be 254 executeTimeStamp here */
                final long value = getNextLittleEndian32UnsignedLong();
                readedIndex += 4; /* ignore other */
                return value;
        }
    }

    /**
     * Return fix length string from bytes.
     */
    public final String getFixLengthStringWithNullTerminateCheckFromEffectiveInitialIndex(
            final int effectiveInitialIndexOffset, final int length) {
        return getFixLengthStringWithNullTerminateCheckFromEffectiveInitialIndex(effectiveInitialIndexOffset, length,
                ISO_8859_1);
    }

    /**
     * Return next fix length string from bytes.
     */
    public final String getFixLengthStringWithNullTerminateCheck(final int length) {
        return getFixLengthStringWithNullTerminateCheck(length, ISO_8859_1);
    }

    /**
     * Return fix length string from bytes.
     */
    public final String getFixLengthStringWithNullTerminateCheckFromEffectiveInitialIndex(
            final int effectiveInitialIndexOffset, final int length, String charsetName) {
        if (effectiveInitialIndexOffset + length > limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + length)));

        final int from = effectiveInitialIndex + effectiveInitialIndexOffset;
        final int end = from + length;
        byte[] bytes = this.bytes;
        int found = from;
        for (; (found < end) && bytes[found] != '\0'; found++) {
            /* empty loop */
        }
        try {
            return new String(bytes, from, found - from, charsetName);
        } catch (UnsupportedEncodingException e) {
            throw new IllegalArgumentException("Unsupported encoding: " + charsetName, e);
        }
    }

    /**
     * Return next fix length string from bytes.
     */
    public final String getFixLengthStringWithNullTerminateCheck(final int length, String charsetName) {
        if (readedIndex + length > effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex + length - effectiveInitialIndex));

        final int from = readedIndex;
        final int end = from + length;
        byte[] bytes = this.bytes;
        int found = from;
        for (; (found < end) && bytes[found] != '\0'; found++) {
            /* empty loop */
        }
        try {
            String string = new String(bytes, from, found - from, charsetName);
            readedIndex += length;
            return string;
        } catch (UnsupportedEncodingException e) {
            throw new IllegalArgumentException("Unsupported encoding: " + charsetName, e);
        }
    }

    /**
     * Return fix-length string from bytes without null-terminate checking
     */
    public final String getFixLengthStringWithoutNullTerminateCheckFromEffectiveInitialIndex(
            final int effectiveInitialIndexOffset, final int length, String charsetName) {
        if (effectiveInitialIndexOffset + length > limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (effectiveInitialIndexOffset < 0 ? effectiveInitialIndexOffset
                            : (effectiveInitialIndexOffset + length)));

        try {
            return new String(bytes, effectiveInitialIndex + effectiveInitialIndexOffset, length, charsetName);
        } catch (UnsupportedEncodingException e) {
            throw new IllegalArgumentException("Unsupported encoding: " + charsetName, e);
        }
    }

    /**
     * Return next fix-length string from bytes without null-terminate checking.
     */
    public final String getFixLengthStringWithoutNullTerminateCheck(final int length, String charsetName) {
        if (readedIndex + length > effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex + length - effectiveInitialIndex));

        try {
            String string = new String(bytes, readedIndex, length, charsetName);
            readedIndex += length;
            return string;
        } catch (UnsupportedEncodingException e) {
            throw new IllegalArgumentException("Unsupported encoding: " + charsetName, e);
        }
    }

    /**
     * Return dynamic length string from bytes.
     */
    public final String getDynamicLengthStringFromEffectiveInitialIndex(final int effectiveInitialIndexOffset) {
        return getDynamicLengthStringFromEffectiveInitialIndex(effectiveInitialIndexOffset, ISO_8859_1);
    }

    /**
     * Return next dynamic length string from bytes.
     */
    public final String getNextDynamicLengthString() {
        return getNextDynamicLengthString(ISO_8859_1);
    }

    /**
     * Return dynamic length string from bytes.
     */
    public final String getDynamicLengthStringFromEffectiveInitialIndex(final int effectiveInitialIndexOffset,
                                                                        String charsetName) {
        if (effectiveInitialIndexOffset >= limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException("newLimit excceed: " + effectiveInitialIndexOffset);

        byte[] bytes = this.bytes;
        final int length = (0xff & bytes[effectiveInitialIndex + effectiveInitialIndexOffset]);
        if (effectiveInitialIndexOffset + length + 1 > limit)
            throw new IllegalArgumentException("newLimit excceed: " + (effectiveInitialIndexOffset + length + 1));

        try {
            return new String(bytes, effectiveInitialIndex + effectiveInitialIndexOffset + 1, length, charsetName);
        } catch (UnsupportedEncodingException e) {
            throw new IllegalArgumentException("Unsupported encoding: " + charsetName, e);
        }
    }

    /**
     * Return next dynamic length string from bytes.
     */
    public final String getNextDynamicLengthString(String charsetName) {
        if (readedIndex >= effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + readedIndex);

        byte[] bytes = this.bytes;
        final int length = (0xff & bytes[readedIndex]);
        if (readedIndex + length + 1 > effectiveInitialIndex + limit)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (readedIndex + length + 1 - effectiveInitialIndex));

        try {
            String string = new String(bytes, readedIndex + 1, length, charsetName);
            readedIndex += length + 1;
            return string;
        } catch (UnsupportedEncodingException e) {
            throw new IllegalArgumentException("Unsupported encoding: " + charsetName, e);
        }
    }

    /**
     * Return big decimal from bytes.
     */
    public final BigDecimal getDecimal(final int pos, final int precision, final int scale) {
        final int precisionNum = precision - scale;
        final int scaleNum = scale;
        final int intg0 = precisionNum / DIG_PER_INT32;
        final int frac0 = scaleNum / DIG_PER_INT32;
        final int intg0x = precisionNum - intg0 * DIG_PER_INT32;
        final int frac0x = scaleNum - frac0 * DIG_PER_INT32;

        final int binSize = intg0 * SIZE_OF_INT32 + dig2bytes[intg0x] + frac0 * SIZE_OF_INT32 + dig2bytes[frac0x];
        if (pos + binSize > limit || pos < 0) {
            throw new IllegalArgumentException("newLimit excceed: " + (pos < 0 ? pos : (pos + binSize)));
        }
        return getDecimal0(effectiveInitialIndex + pos, precisionNum, scaleNum, // NL
                intg0, frac0, intg0x, frac0x);
    }

    /**
     * Return next big decimal from bytes.
     */
    public final BigDecimal getDecimal(final int precision, final int scale) {
        final int precisionNum = precision - scale;
        final int scaleNum = scale;
        final int intg0 = precisionNum / DIG_PER_INT32;
        final int frac0 = scaleNum / DIG_PER_INT32;
        final int intg0x = precisionNum - intg0 * DIG_PER_INT32;
        final int frac0x = scaleNum - frac0 * DIG_PER_INT32;

        final int binSize = intg0 * SIZE_OF_INT32 + dig2bytes[intg0x] + frac0 * SIZE_OF_INT32 + dig2bytes[frac0x];
        if (readedIndex + binSize > effectiveInitialIndex + limit) {
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex + binSize - effectiveInitialIndex));
        }

        BigDecimal bigDecimal = getDecimal0(readedIndex, precisionNum, scaleNum, // NL
                intg0, frac0, intg0x, frac0x);
        readedIndex += binSize;
        return bigDecimal;
    }

    /**
     * Return big decimal from bytes.
     *
     * <pre>
     * Decimal representation in protogenesis seems decode be as follows:
     *
     * 1st bit - sign such that set == +, unset == -
     * every 4 bytes represent 9 digits in big-endian order, so that
     * if you print the values of these quads as big-endian integers one after
     * another, you get the whole number string representation in decimal. What
     * remains is decode put a sign and a decimal dot.
     *
     * 80 00 00 05 1b 38 b0 60 00 means:
     *
     *   0x80 - positive
     *   0x00000005 - 5
     *   0x1b38b060 - 456700000
     *   0x00       - 0
     *
     * 54567000000 / 10^{10} = 5.4567
     * </pre>
     */
    private final BigDecimal getDecimal0(final int begin, final int intg, final int frac, final int intg0,
                                         final int frac0, final int intg0x, final int frac0x) {
        final int mask = ((bytes[begin] & 0x80) == 0x80) ? 0 : -1;
        int from = begin;

        /* max string length */
        final int len = ((mask != 0) ? 1 : 0) + ((intg != 0) ? intg : 1) // NL
                + ((frac != 0) ? 1 : 0) + frac;
        char[] buf = new char[len];
        int pos = 0;

        if (mask != 0) /* decimal sign */
            buf[pos++] = ('-');

        final byte[] d_copy = bytes;
        d_copy[begin] ^= 0x80; /* clear sign */
        int mark = pos;

        if (intg0x != 0) {
            final int i = dig2bytes[intg0x];
            int x = 0;
            switch (i) {
                case 1:
                    x = d_copy[from] /* one byte */;
                    break;
                case 2:
                    x = getBigEndian16SignedInt(d_copy, from);
                    break;
                case 3:
                    x = getBigEndian24SignedInt(d_copy, from);
                    break;
                case 4:
                    x = getBigEndian32SignedInt(d_copy, from);
                    break;
            }
            from += i;
            x ^= mask;
            if (x < 0 || x >= powers10[intg0x + 1]) {
                throw new IllegalArgumentException("bad format, x exceed: " + x + ", " + powers10[intg0x + 1]);
            }
            if (x != 0 /* !digit || x != 0 */) {
                for (int j = intg0x; j > 0; j--) {
                    final int divisor = powers10[j - 1];
                    final int y = x / divisor;
                    if (mark < pos || y != 0) {
                        buf[pos++] = ((char) ('0' + y));
                    }
                    x -= y * divisor;
                }
            }
        }

        for (final int stop = from + intg0 * SIZE_OF_INT32; from < stop; from += SIZE_OF_INT32) {
            int x = getBigEndian32SignedInt(d_copy, from);
            x ^= mask;
            if (x < 0 || x > DIG_MAX) {
                throw new IllegalArgumentException("bad format, x exceed: " + x + ", " + DIG_MAX);
            }
            if (x != 0) {
                if (mark < pos) {
                    for (int i = DIG_PER_DEC1; i > 0; i--) {
                        final int divisor = powers10[i - 1];
                        final int y = x / divisor;
                        buf[pos++] = ((char) ('0' + y));
                        x -= y * divisor;
                    }
                } else {
                    for (int i = DIG_PER_DEC1; i > 0; i--) {
                        final int divisor = powers10[i - 1];
                        final int y = x / divisor;
                        if (mark < pos || y != 0) {
                            buf[pos++] = ((char) ('0' + y));
                        }
                        x -= y * divisor;
                    }
                }
            } else if (mark < pos) {
                for (int i = DIG_PER_DEC1; i > 0; i--)
                    buf[pos++] = ('0');
            }
        }

        if (mark == pos)
            /* fix 0.0 problem, only '.' may cause BigDecimal parsing exception. */
            buf[pos++] = ('0');

        if (frac > 0) {
            buf[pos++] = ('.');
            mark = pos;

            for (final int stop = from + frac0 * SIZE_OF_INT32; from < stop; from += SIZE_OF_INT32) {
                int x = getBigEndian32SignedInt(d_copy, from);
                x ^= mask;
                if (x < 0 || x > DIG_MAX) {
                    throw new IllegalArgumentException("bad format, x exceed: " + x + ", " + DIG_MAX);
                }
                if (x != 0) {
                    for (int i = DIG_PER_DEC1; i > 0; i--) {
                        final int divisor = powers10[i - 1];
                        final int y = x / divisor;
                        buf[pos++] = ((char) ('0' + y));
                        x -= y * divisor;
                    }
                } else {
                    for (int i = DIG_PER_DEC1; i > 0; i--)
                        buf[pos++] = ('0');
                }
            }

            if (frac0x != 0) {
                final int i = dig2bytes[frac0x];
                int x = 0;
                switch (i) {
                    case 1:
                        x = d_copy[from] /* one byte */;
                        break;
                    case 2:
                        x = getBigEndian16SignedInt(d_copy, from);
                        break;
                    case 3:
                        x = getBigEndian24SignedInt(d_copy, from);
                        break;
                    case 4:
                        x = getBigEndian32SignedInt(d_copy, from);
                        break;
                }
                x ^= mask;
                if (x != 0) {
                    final int dig = DIG_PER_DEC1 - frac0x;
                    x *= powers10[dig];
                    if (x < 0 || x > DIG_MAX) {
                        throw new IllegalArgumentException("bad format, x exceed: " + x + ", " + DIG_MAX);
                    }
                    for (int j = DIG_PER_DEC1; j > dig; j--) {
                        final int divisor = powers10[j - 1];
                        final int y = x / divisor;
                        buf[pos++] = ((char) ('0' + y));
                        x -= y * divisor;
                    }
                }
            }

            if (mark == pos)
                /* make number more friendly */
                buf[pos++] = ('0');
        }

        d_copy[begin] ^= 0x80; /* restore sign */
        String decimal = String.valueOf(buf, 0, pos);
        return new BigDecimal(decimal);
    }

    /**
     * Fill MY_BITMAP structure from bytes.
     *
     * @param len The length of MY_BITMAP in bits.
     */
    public final void fillBitmap(BitSet bitmap, final int pos, final int len) {
        if (pos + ((len + 7) / 8) > limit || pos < 0)
            throw new IllegalArgumentException("newLimit excceed: " + (pos + (len + 7) / 8));

        fillBitmap0(bitmap, effectiveInitialIndex + pos, len);
    }

    /**
     * Fill next MY_BITMAP structure from bytes.
     *
     * @param length The length of MY_BITMAP in bits.
     */
    public final void fillBitmap(BitSet bitSet, final int length) {
        if (readedIndex + ((length + 7) / 8) > effectiveInitialIndex + limit)
            throw new IllegalArgumentException(
                    "newLimit excceed: " + (readedIndex + ((length + 7) / 8) - effectiveInitialIndex));

        readedIndex = fillBitmap0(bitSet, readedIndex, length);
    }

    /**
     * Fill MY_BITMAP structure from bytes.
     *
     * @param length The length of MY_BITMAP in bits.
     */
    private final int fillBitmap0(BitSet bitSet, int index, final int length) {
        final byte[] bytes = this.bytes;

        for (int bit = 0; bit < length; bit += 8) {
            int flag = ((int) bytes[index++]) & 0xff;
            if (flag == 0) {
                continue;
            }
            if ((flag & 0x01) != 0)
                bitSet.set(bit);
            if ((flag & 0x02) != 0)
                bitSet.set(bit + 1);
            if ((flag & 0x04) != 0)
                bitSet.set(bit + 2);
            if ((flag & 0x08) != 0)
                bitSet.set(bit + 3);
            if ((flag & 0x10) != 0)
                bitSet.set(bit + 4);
            if ((flag & 0x20) != 0)
                bitSet.set(bit + 5);
            if ((flag & 0x40) != 0)
                bitSet.set(bit + 6);
            if ((flag & 0x80) != 0)
                bitSet.set(bit + 7);
        }
        return index;
    }

    /**
     * Return next MY_BITMAP structure from bytes.
     *
     * @param length The length of MY_BITMAP in bits.
     */
    public final BitSet getBitSet(final int length) {
        BitSet bitSet = new BitSet(length);
        fillBitmap(bitSet, length);
        return bitSet;
    }
    //

    /**
     * Return all remaining data from bytes.
     */
    public final byte[] bytesCopy() {
        return bytesCopy(0, limit);
    }

    /**
     * Return n-byte data from bytes.
     */
    public final byte[] bytesCopy(final int effectiveInitialIndexOffset, final int length) {
        byte[] bytes = new byte[length];
        bytesCopy(effectiveInitialIndexOffset, bytes, 0, length);
        return bytes;
    }

    /**
     * Fill n bytes in this bytes.
     */
    public final void bytesCopy(final int effectiveInitialIndexOffset, byte[] bytes, final int bytesStartIndex, final int length) {
        if (effectiveInitialIndexOffset + length > limit || effectiveInitialIndexOffset < 0)
            throw new IllegalArgumentException("newLimit excceed: " + (effectiveInitialIndexOffset + length));

        System.arraycopy(this.bytes, effectiveInitialIndex + effectiveInitialIndexOffset, bytes, bytesStartIndex, length);
    }
    //

    /**
     * Return next n-byte data from bytes.
     */
    public final byte[] getBytes(final int length) {
        byte[] bytes = new byte[length];
        getBytes(bytes, 0, length);
        return bytes;
    }

    /**
     * Fill next n bytes in this bytes.
     */
    public final void getBytes(byte[] bytes, final int bytesStartIndex, final int length) {
        if (readedIndex + length > effectiveInitialIndex + limit)
            throw new IllegalArgumentException("newLimit excceed: " + (readedIndex + length - effectiveInitialIndex));

        System.arraycopy(this.bytes, readedIndex, bytes, bytesStartIndex, length);
        readedIndex += length;
    }


}
